package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassDescription:  方法调用链 （责任链模式）
 * @JdkVersion: 1.8
 * @Author: libs
 * @Created: 2024/11/26 14:46
 */
public class A18_1 {
    static class Target {
        public void foo() {
            System.out.println("target1 foo");
        }
    }

    static class Advice1 implements MethodInterceptor{
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before Advice1");
            Object proceed = invocation.proceed();
            System.out.println("after Advice1");
            return proceed;
        }
    }

    static class Advice2 implements MethodInterceptor{
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before Advice2");
            Object proceed = invocation.proceed();
            System.out.println("after Advice2");
            return proceed;
        }
    }

    static class MyInvocation implements MethodInvocation{

        public Object target;
        public Method method;
        public Object[] args;
        public List<MethodInterceptor> methodInterceptorList;
        public int count;

        public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) {
            this.target = target;
            this.method = method;
            this.args = args;
            this.methodInterceptorList = methodInterceptorList;
            this.count = 1;
        }

        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return args;
        }

        @Override
        public Object proceed() throws Throwable { // 调用给每一个环绕通知，调用目标
            if (count > methodInterceptorList.size()){
                // 调用目标并返回递归
                return method.invoke(target, args);
            }
            // 逐一调用通知
            MethodInterceptor methodInterceptor = methodInterceptorList.get(count - 1);
            count++;
            return methodInterceptor.invoke(this);
        }

        @Override
        public Object getThis() {
            return this;
        }

        @Override
        public AccessibleObject getStaticPart() {
            return method;
        }
    }

    public static void main(String[] args) throws Throwable {
        Target target = new Target();
        List<MethodInterceptor> methodInterceptors = new ArrayList<>();
        methodInterceptors.add(new Advice1());
        methodInterceptors.add(new Advice2());
        MyInvocation foo = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], methodInterceptors);
        Object proceed = foo.proceed();
    }

}
